#include <stdio.h>
#include <stdlib.h>

typedef struct node {
	size_t key;
	int status;
	size_t size;
	void *point;
	struct node *next;
} node;
typedef node *list;

typedef struct stAllocator {
	void *mem;
	size_t total_size;
	list memory_list;
	size_t block_size;
	size_t number_blocks;
} stAllocator;

stAllocator allocator;
size_t identifiers[10000];
size_t counter = 1;

int insert(list *st_list, size_t size) {
	node *temp = (node*)malloc(sizeof(node));
	temp->key = counter++;
	temp->status = 0;
	temp->size = size;
	temp->point = (((*st_list)->point) + allocator.block_size);
	temp->next = *st_list;
	*st_list = temp;
	return 0;
}

int create(list *st_list, size_t size) {
	node *temp = (node*)malloc(sizeof(node));
	*st_list = temp;
	(*st_list)->key = counter++;
	(*st_list)->status = 0;
	(*st_list)->size = size;
	(*st_list)->point = allocator.mem;
	(*st_list)->next = NULL;
	return 0;
}

int ma_init(size_t mem) {
	allocator.block_size = 16;
	allocator.mem = malloc(mem);
	if (allocator.mem == NULL)
		return 1;
	allocator.total_size = mem;
	
	if (mem % allocator.block_size == 0)
		allocator.number_blocks = mem / allocator.block_size;
	else
		allocator.number_blocks = mem / allocator.block_size + 1;
	for (size_t i = 0; i < allocator.number_blocks; i++) 
		if (i == allocator.number_blocks - 1) 
			insert(&allocator.memory_list, mem % allocator.block_size);
		else if (i == 0) 
			create(&allocator.memory_list, allocator.block_size);
		else 
			insert(&allocator.memory_list, allocator.block_size);
	
	return 0;
}

void ma_deinit(list *head) {
	free(allocator.mem);
	list temp = *head;
	while (*head != NULL) {
		temp = *head;
		free(temp);
		*head = (*head)->next;
	}
	return;
}

int ma_free(size_t id) {
	if ((id <= 0) || (id > counter))
		return 1;
	node *temp = allocator.memory_list;
	while (temp != NULL) {
		if (temp->key == id) {
			temp->status = 0;
			break;
		}
		temp = temp->next;
	}
	return 0;
}

size_t ma_alloc(size_t sz) {
	node *temp = allocator.memory_list;
	if (sz <= allocator.block_size)
		while (temp != NULL) {
			if ((temp->status == 0) && (temp->size >= sz)) {
				temp->status = 1;
				return temp->key;
			}
			temp = temp->next;
		}
	else {
		int block_counter = 0;
		size_t total_memory = 0;
		int flag = 0;
		int result_id;
		node *first_node_status;
		while ((temp != NULL) && (total_memory < sz)) {
			if (temp->status == 0) {
				if (flag == 0) {
					flag = 1;
					first_node_status = temp;
				}
				block_counter++;
				total_memory += temp->size;
				result_id = temp->key;
			}
			else {
				if (flag == 1) {
					flag = 0;
					total_memory = 0;
					block_counter = 0;
				}
			}
			temp = temp->next;
		}
		if (total_memory >= sz) {
			for (int i = 1; i <= block_counter; i++) {
				first_node_status->status = 1;
				first_node_status = first_node_status->next;
			}
			printf("number_blocks = %d\n", block_counter);
			
			return result_id; 
		}
	}
	return 0;
}

void* ma_get(size_t id) {
	node *temp = allocator.memory_list;
	while (temp != NULL) {
		if (temp->key == id) {
			printf("key = %lu\n", temp->key);
			return temp->point;
			break;
		}
		temp = temp->next;
	}
	return NULL;
}

int main() {
	if (ma_init(900) == 1) {
		printf("Allocator failed\n");
	}
	ma_deinit(&allocator.memory_list);
	
	return 0;
}
